/**
 * CoffeeMilk (C) 2010 Amen Hamdan
 * 
 * See the NOTICE file distributed with this work for additional 
 * information regarding copyright ownership.  This file is licenses
 * to you under the Apache License, Version 2.0 (the "License"); you 
 * may not use this file except in compliance with the License.  You 
 * may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 * implied. See the License for the specific language governing 
 * permissions and limitations under the License.    
 * 
 */
package ameen.rtm.coffeemilk.ui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

import ameen.rtm.coffeemilk.RtmTaskListModel;
import ameen.rtm.coffeemilk.ui.cellrenderer.ListTableCellRenderer;
import ameen.rtm.coffeemilk.ui.cellrenderer.TaskTableCellRenderer;
import ameen.rtm.coffeemilk.ui.tablemodel.TaskListTableModel;
import ameen.rtm.coffeemilk.ui.tablemodel.TaskSelectionModel;
import ameen.rtm.coffeemilk.ui.tablemodel.TasksTableModel;
import ameen.rtm.coffeemilk.ui.util.ToolbarFactory;
import ameen.rtm.lib.types.RtmList;
import ameen.rtm.lib.types.RtmTask;
import ameen.rtm.lib.types.TasksVector;

public class TaskListPanel extends JScrollPane {
	private RtmTask dragDropTask;
	private JTable dragDropTargetTable; 
	private Map<String, NotesEditFrame> notesEditFrameMap = new HashMap<String, NotesEditFrame>();
	
	private final class ListTableMouseAdapter extends MouseAdapter {
		private final RtmList currentEntry;
		private final JTable taskDetailsTable;
		private final JTable groupTitleTable;

		private ListTableMouseAdapter(final RtmList currentEntry, final TasksVector tasksVector, final JTable taskDetailsTable, final JTable groupTitleTable) {
			this.currentEntry = currentEntry;
			this.taskDetailsTable = taskDetailsTable;
			this.groupTitleTable = groupTitleTable;
			
			PropertyChangeListener pcl = new PropertyChangeListener() {
				@Override
				public void propertyChange(PropertyChangeEvent evt) {
					if(evt.getPropertyName().equals(RtmList.TASK_ADDED)) {
						updateExpandState();
					} else if (evt.getPropertyName().equals(TasksVector.ELEMENT_REMOVED)) {
						if(currentEntry.getTaskCount() == 0) {
							currentEntry.setExpanded(false);
							updateExpandState();
						}
					}
				}
			};
			currentEntry.addPropertyChangeListener(pcl);
			tasksVector.addPropertyChangeListener(pcl);
		}

		@Override
		public void mouseClicked(MouseEvent e) {
			int row = groupTitleTable.rowAtPoint(e.getPoint());
			int col = groupTitleTable.columnAtPoint(e.getPoint());
			
			groupTitleTable.getValueAt(row, col);
			if( (row == 0) & (col == 0) ) {
				currentEntry.setExpanded(!currentEntry.isExpanded());
				updateExpandState();
			}
			groupTitleTable.requestFocus();
		}

		private void updateExpandState() {
			if(currentEntry.isExpanded()) {
				taskDetailsTable.setVisible(true);
			} else {
				taskDetailsTable.setVisible(false);
			}
		}
		
		@Override
		public void mouseEntered(MouseEvent e) {
			if(dragDropTask != null) {
				LineBorder lineBorder = new LineBorder(Color.BLUE, 1, true);
				groupTitleTable.setBorder(lineBorder);
				dragDropTargetTable = groupTitleTable;
			}
		}
		@Override
		public void mouseExited(MouseEvent e) {
			if(dragDropTask != null) {
				Color color = new Color(240, 240, 240);	
				LineBorder lineBorder = new LineBorder(color, 1, true);
				groupTitleTable.setBorder(lineBorder);
				dragDropTargetTable = null;
			}
		}
	}

	private final class TasksTableMouseAdapter extends MouseAdapter {
		private final JTable taskDetailsTable;
		private final RtmList currentEntry;

		private TasksTableMouseAdapter(JTable taskDetailsTable, RtmList currentEntry) {
			this.taskDetailsTable = taskDetailsTable;
			this.currentEntry = currentEntry;
		}

		@Override
		public void mouseClicked(MouseEvent e) {
			final int row = taskDetailsTable.rowAtPoint(e.getPoint());
			final int col = taskDetailsTable.columnAtPoint(e.getPoint());

			JPopupMenu menu;
			switch(col) {
			case(0): 
		        menu = ToolbarFactory.createPrioritySelectionPopup(taskListModel, currentEntry, row);
		        menu.show(taskDetailsTable, e.getPoint().x, e.getPoint().y);
		        break;
		        
			case(1):
				SwingUtilities.invokeLater(new Runnable() {
					
					@Override
					public void run() {
						RtmTask currentTask = taskListModel.getTasks(currentEntry).get(row);
						currentTask.setCompleted(!currentTask.isCompleted());
					}
				});
				break;
				
			case(4):
		        menu = ToolbarFactory.createEditTaskPopup(taskListModel, currentEntry, row);
		        menu.show(taskDetailsTable, e.getPoint().x-250, e.getPoint().y);
		        break;
	
			case(5):
				RtmTask currentTask = taskListModel.getTasks(currentEntry).get(row);
				NotesEditFrame notesFrame = notesEditFrameMap.get(currentTask.getId());
				if(notesFrame == null) {
					notesFrame = new NotesEditFrame(currentTask);
					notesEditFrameMap.put(currentTask.getId(), notesFrame);
				}
				if(!notesFrame.isVisible()) {
					notesFrame.setVisible(true);
				} else {
					notesFrame.toFront();
				}
		        break;
			}		}

		@Override
		public void mousePressed(MouseEvent e) {
			final int col = taskDetailsTable.columnAtPoint(e.getPoint());
			
			if( (col == 2) || (col == 3) ) {
				taskDetailsTable.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
				int row = taskDetailsTable.rowAtPoint(e.getPoint());
				dragDropTask = taskListModel.getTasks(currentEntry).get(row);
			}
		}
		@Override
		public void mouseReleased(MouseEvent e) {
			taskDetailsTable.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			
				SwingUtilities.invokeLater(new Runnable() {
					@Override
					public void run() {
						if(dragDropTargetTable != null) {
							Color color = new Color(240, 240, 240);	
							LineBorder lineBorder = new LineBorder(color, 1, true);
							dragDropTargetTable.setBorder(lineBorder);

							RtmList listEntry = ((TaskListTableModel)dragDropTargetTable.getModel()).getListEntry();
							if(listEntry.getId().equals(dragDropTask.getListId())) {
								dragDropTargetTable = null;
								dragDropTask = null;
								return;
							}
							dragDropTask.setTargetMoveList(listEntry);
						}
						dragDropTargetTable = null;
						dragDropTask = null;
					}
				});
		}
	}

	private static final long serialVersionUID = 1L;
	private JPanel taskGroupPanel = null;
	private RtmTaskListModel taskListModel;
	
	public TaskListPanel() {
		super();
		initialize();
	}

	public void setTaskListModel(RtmTaskListModel taskListModel) {
		this.taskListModel = taskListModel;
		reloadTaskView();
	}

	private void reloadTaskView() {
		for(final RtmList currentEntry : taskListModel.getLists()) {
			final JTable groupTitleTable = createGroupTitleTable();
			groupTitleTable.setEnabled(false);
			
			final JTable taskDetailsTable = createTaskDetailsTable();
			taskDetailsTable.setSelectionModel(new TaskSelectionModel());

			taskGroupPanel.add(groupTitleTable, null);
			taskGroupPanel.add(taskDetailsTable, null);
			groupTitleTable.setModel(new TaskListTableModel(currentEntry));
			taskDetailsTable.setModel(new TasksTableModel(taskListModel.getTasks(currentEntry)));
		
			groupTitleTable.setRowHeight(30);
			taskDetailsTable.setRowHeight(30);
		
			taskDetailsTable.addMouseListener(new TasksTableMouseAdapter(taskDetailsTable, currentEntry));
			groupTitleTable.addMouseListener(new ListTableMouseAdapter(currentEntry, taskListModel.getTasks(currentEntry),
																	   taskDetailsTable, groupTitleTable));

			updateCellFormat(groupTitleTable, new ListTableCellRenderer(currentEntry), 0, 27);
			updateCellFormat(groupTitleTable, new ListTableCellRenderer(currentEntry), 2, 80);
		
			Vector<RtmTask> tasks = taskListModel.getTasks(currentEntry);
			updateCellFormat(taskDetailsTable, new TaskTableCellRenderer(tasks), 0, 12);
			updateCellFormat(taskDetailsTable, new TaskTableCellRenderer(tasks), 1, 25);
			updateCellFormat(taskDetailsTable, new TaskTableCellRenderer(tasks), 2, -1);
			updateCellFormat(taskDetailsTable, new TaskTableCellRenderer(tasks), 3, 100);
			updateCellFormat(taskDetailsTable, new TaskTableCellRenderer(tasks), 4, 30);
			updateCellFormat(taskDetailsTable, new TaskTableCellRenderer(tasks), 5, 30);
		}
	}
	
	private void updateCellFormat(JTable table, TableCellRenderer renderer, int column, int width) {
		TableColumn tableColumn = table.getColumnModel().getColumn(column);
		
		tableColumn.setCellRenderer(renderer);
		
		if(width != -1) {
			tableColumn.setMinWidth(width);
			tableColumn.setMaxWidth(width);
		}
	}
	
	private void initialize() {
		this.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		this.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		this.getVerticalScrollBar().setUnitIncrement(16);
		this.getViewport().add(getTaskGroupPanel());
	}

	private JPanel getTaskGroupPanel() {
		if (taskGroupPanel == null) {
			taskGroupPanel = new JPanel();
			taskGroupPanel.setLayout(new BoxLayout(getTaskGroupPanel(), BoxLayout.Y_AXIS));
		}
		taskGroupPanel.setSize(new Dimension(300, 500));
		return taskGroupPanel;
	}

	private JTable createGroupTitleTable() {
		JTable groupTitleTable;
		groupTitleTable = new JTable();
		groupTitleTable.setShowHorizontalLines(false);
		groupTitleTable.setShowVerticalLines(false);
		Color color = new Color(240, 240, 240);
		LineBorder lineBorder = new LineBorder(color, 1, true);
		groupTitleTable.setBorder(lineBorder);
		groupTitleTable.setEnabled(false);
		groupTitleTable.setFont(new Font("Dialog", Font.BOLD, 18));
		groupTitleTable.setBackground(new Color(250, 250, 250));
		
		return groupTitleTable;
	}

	private JTable createTaskDetailsTable() {
		JTable taskDetailsTable;
		taskDetailsTable = new JTable();
		Color color = new Color(240, 240, 240);
		LineBorder lineBorder = new LineBorder(color, 1, true);
		taskDetailsTable.setBorder(lineBorder);
		taskDetailsTable.setFont(new Font("Dialog", Font.PLAIN, 14));
		taskDetailsTable.setShowHorizontalLines(false);
		taskDetailsTable.setShowVerticalLines(false);
		
		return taskDetailsTable;
	}
}
